/**
 * @file bsp_xspi.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "hal_adapter.h"
#if defined(STM32H563xx)
#include "bsp_xspi.h"


#define XSPI_CS_PORT GPIOG
#define XSPI_CS_PIN GPIO_PIN_6
#define xspi_cs_enable(x)                                                 \
    {                                                                     \
        if (x)                                                            \
            HAL_GPIO_WritePin(XSPI_CS_PORT, XSPI_CS_PIN, GPIO_PIN_RESET); \
        else                                                              \
            HAL_GPIO_WritePin(XSPI_CS_PORT, XSPI_CS_PIN, GPIO_PIN_SET);   \
    }

#define XSPI_IO0_PORT GPIOD
#define XSPI_IO0_PIN GPIO_PIN_11
#define xspi_io0(x)                                                         \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO0_PORT, XSPI_IO0_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO0_PORT, XSPI_IO0_PIN, GPIO_PIN_RESET); \
    }
#define xspi_io0_bit() HAL_GPIO_ReadPin(XSPI_IO0_PORT, XSPI_IO0_PIN) ? 1 : 0

#define XSPI_IO1_PORT GPIOF
#define XSPI_IO1_PIN GPIO_PIN_9
#define xspi_io1(x)                                                         \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO1_PORT, XSPI_IO1_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO1_PORT, XSPI_IO1_PIN, GPIO_PIN_RESET); \
    }
#define xspi_io1_bit() HAL_GPIO_ReadPin(XSPI_IO1_PORT, XSPI_IO1_PIN) ? 1 : 0

#define XSPI_IO2_PORT GPIOF
#define XSPI_IO2_PIN GPIO_PIN_7
#define xspi_io2(x)                                                         \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO2_PORT, XSPI_IO2_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO2_PORT, XSPI_IO2_PIN, GPIO_PIN_RESET); \
    }
#define xspi_io2_bit() HAL_GPIO_ReadPin(XSPI_IO2_PORT, XSPI_IO2_PIN) ? 1 : 0

#define XSPI_IO3_PORT GPIOF
#define XSPI_IO3_PIN GPIO_PIN_6
#define xspi_io3(x)                                                         \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO3_PORT, XSPI_IO3_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO3_PORT, XSPI_IO3_PIN, GPIO_PIN_RESET); \
    }
#define xspi_io3_bit() HAL_GPIO_ReadPin(XSPI_IO3_PORT, XSPI_IO3_PIN) ? 1 : 0

#define XSPI_CLK_PORT GPIOB
#define XSPI_CLK_PIN GPIO_PIN_2
#define xspi_clk(x)                                                         \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_CLK_PORT, XSPI_CLK_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_CLK_PORT, XSPI_CLK_PIN, GPIO_PIN_RESET); \
    }

#define xspi_mosi(x)                                                        \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO0_PORT, XSPI_IO0_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO0_PORT, XSPI_IO0_PIN, GPIO_PIN_RESET); \
    }
#define xspi_miso_bit() HAL_GPIO_ReadPin(XSPI_IO1_PORT, XSPI_IO1_PIN) ? 1 : 0
#define xspi_wp_enable(x)                                                   \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO2_PORT, XSPI_IO2_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO2_PORT, XSPI_IO2_PIN, GPIO_PIN_RESET); \
    }

#define xspi_hold_enable(x)                                                 \
    {                                                                       \
        if (x)                                                              \
            HAL_GPIO_WritePin(XSPI_IO3_PORT, XSPI_IO3_PIN, GPIO_PIN_SET);   \
        else                                                                \
            HAL_GPIO_WritePin(XSPI_IO3_PORT, XSPI_IO3_PIN, GPIO_PIN_RESET); \
    }

#define xspi_delay_ms(x) HAL_Delay(x)
#define xspi_delay_us(x)                     \
    {                                        \
        for (int32_t i = x * 5; i >= 0; i--) \
            asm("nop");                      \
    }

void xspi_direction_input(void)
{
    HAL_GPIO_DeInit(XSPI_IO2_PORT, XSPI_IO2_PIN);
    HAL_GPIO_DeInit(XSPI_IO1_PORT, XSPI_IO1_PIN);
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    
    /* IO2 & WP# */
    GPIO_InitStruct.Pin =  XSPI_IO2_PIN;
    HAL_GPIO_Init(XSPI_IO2_PORT, &GPIO_InitStruct);

    /* IO1 & MISO */
    GPIO_InitStruct.Pin =  XSPI_IO1_PIN;
    HAL_GPIO_Init(XSPI_IO1_PORT, &GPIO_InitStruct);
}

void xspi_direction_output(void)
{
    HAL_GPIO_DeInit(XSPI_IO2_PORT, XSPI_IO2_PIN);
    HAL_GPIO_DeInit(XSPI_IO1_PORT, XSPI_IO1_PIN);
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    /* IO2 & WP# */
    GPIO_InitStruct.Pin =  XSPI_IO2_PIN;
    HAL_GPIO_Init(XSPI_IO2_PORT, &GPIO_InitStruct);

    /* IO1 & MISO */
    GPIO_InitStruct.Pin =  XSPI_IO1_PIN;
    HAL_GPIO_Init(XSPI_IO1_PORT, &GPIO_InitStruct);
}

int32_t bsp_xspi_init(void)
{
    /** OCTOSPI1 GPIO Configuration
        PG6     ------> OCTOSPI1_NCS
        PF7     ------> OCTOSPI1_IO2 & WP#
        PF6     ------> OCTOSPI1_IO3 & HOOLD#
        PF9     ------> OCTOSPI1_IO1 & MISO
        PB2     ------> OCTOSPI1_CLK
        PD11     ------> OCTOSPI1_IO0 & MOSI
    */

    __HAL_RCC_GPIOG_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* CS# */
    GPIO_InitStruct.Pin = XSPI_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(XSPI_CS_PORT, &GPIO_InitStruct);

    /* CLK */
    GPIO_InitStruct.Pin = XSPI_CLK_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(XSPI_CLK_PORT, &GPIO_InitStruct);
 
    
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    /* IO3 & HOLD# */
    GPIO_InitStruct.Pin =  XSPI_IO3_PIN;
    HAL_GPIO_Init(XSPI_IO3_PORT, &GPIO_InitStruct);

    /* IO2 & WP# */
    GPIO_InitStruct.Pin =  XSPI_IO2_PIN;
    HAL_GPIO_Init(XSPI_IO2_PORT, &GPIO_InitStruct);

    /* IO1 & MISO */
    GPIO_InitStruct.Pin =  XSPI_IO1_PIN;
    HAL_GPIO_Init(XSPI_IO1_PORT, &GPIO_InitStruct);

    /* IO0 & MOSI */
    GPIO_InitStruct.Pin = XSPI_IO0_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(XSPI_IO0_PORT, &GPIO_InitStruct);

    xspi_clk(1);
    xspi_cs_enable(0);
    xspi_wp_enable(1);
    xspi_hold_enable(1);

    return 0;
}

int32_t bsp_xspi_enable(void)
{
    // printf("bsp_xspi_enable \r\n");

    xspi_clk(1);
    xspi_cs_enable(1);

    return 0;
}

int32_t bsp_xspi_disable(void)
{
    // printf("bsp_xspi_disable \r\n");

    xspi_cs_enable(0);
    xspi_clk(1);

    return 0;
}

int32_t bsp_xspi_write(const uint8_t *data, size_t size)
{
    for (uint32_t i = 0; i < size; i++)
    {
        uint8_t reg = data[i];

        for (uint8_t j = 0; j < 8; j++)
        {
            xspi_clk(0);
            xspi_mosi(reg & 0x80 ? 1 : 0);
            reg <<= 1;
            xspi_delay_us(10);
            xspi_clk(1);
            xspi_delay_us(10);
        }
    }

    return size;
}

int32_t bsp_xspi_read(uint8_t *data, size_t size)
{
    // printf("bsp_xspi_read %d\r\n", size);
    uint8_t dat = 0;

    xspi_direction_input();
    for (uint32_t i = 0; i < size; i++)
    {
        for (uint8_t j = 0; j < 8; j++)
        {
            // stand spi mode
            xspi_clk(1);
            xspi_delay_us(10);
            xspi_clk(0);
            xspi_delay_us(10);
            dat = xspi_miso_bit();

            data[i] <<= 1;
            data[i] |= dat;
        }
    }
    xspi_direction_output();
    // printf("bsp_xspi_read exit \r\n");

    return size;
}

#endif
